//
//  queue.c
//  
//
//  Created by chenyh on 2021/1/20.
//

#include "queue.h"
#include <stdlib.h>
#include <stdio.h>
/* 局部函数原型   */
static void CopyToNode(Item item,Node * pnode);
static void CopyToItem(Node * pn,Item * pi);
/// 初始化队列
/// @param pq 指向一个队列
void InitializeQueue(Queue *pq) {
    pq->front = pq->rear = NULL;
    pq->items = 0;
}

bool QueueIsFull(const Queue * pq) {
    return pq->items == MAXQUEUE;
}
bool QueueIsEmpty(const Queue * pq) {
    return pq->items == 0;
}
int  QueueItemCount(const Queue * pq) {
    return pq->items;
}
/*
 把项添加到队列中，包括以下几个步骤：
 1、创建一个新节点；
 2、把项拷贝到节点中；
 3、设置节点的next指针为null，标明该节点是最后一个节点；
 4、设置当前尾节点的next指针指向新节点，把新节点链接到队列中；
 5、把rear指针指向新节点，以便找到最后的节点；
 6、项数加1；
 需要处理两种特殊情况：
 第一：如果队列为空，应该把front指针设置为指向新节点。因为如果队列中只有一个节点，
 那么这个节点既是首节点也是尾节点。
 第二：如果函数不能为节点分配内存，则必须执行一些动作。
 */
bool EnQueue(Item item,Queue * pq) {
    Node *pnew;
    if (QueueIsFull(pq)) {
        return false;
    }
    pnew = (Node *)malloc(sizeof(Node));
    if (pnew == NULL) {
        fprintf(stderr, "Unable to allocate memory!\n");
        exit(1);
    }
    CopyToNode(item, pnew);
    pnew->next = NULL;
    if (QueueIsEmpty(pq)) {
        pq->front = pnew; //项位于队列首端
    }else
        pq->rear->next = pnew;//链接到队列尾端
    pq->rear = pnew; //记录队列尾端的位置
    pq->items++; //队列项数+1
    return true;
}
/*
 从队列的首端删除项，涉及以下几个步骤：
 1、把项拷贝到给定的变量中
 2、释放空出的节点使用的内存空间
 3、重置首指针指向队列中的下一个项
 4、如果删除最后一项，把首指针和尾指针都重置为NULL；
 5、项数减1。
 */
bool DeQueue(Item * pitem,Queue * pq) {
    Node * pt;
    if (QueueIsEmpty(pq)) {
        return false;
    }
    CopyToItem(pq->front,pitem );
    
    pt = pq->front;
    pq->front = pq->front->next;
    free(pt);
    pq->items--;
    if (pq->items == 0)
        pq->rear = NULL;
    return true;
}
void EmptyTheQueue(Queue * pq){
    Item dummy;
    while (!QueueIsEmpty(pq)) {
        DeQueue(&dummy, pq);
    }
}

/* 局部函数定义 */
//把每一个项拷贝到节点中
static void CopyToNode(Item item,Node * pnode)
{
    pnode->item = item;//拷贝结构
}
static void CopyToItem(Node * pnode,Item *pi)
{
    *pi = pnode -> item;
}

